﻿using System;
using System.Threading;
using l1cs.server.datatables;
using l1cs.server.model;
using l1cs.server.model.Instance;
using l1cs.server.templates;

namespace l1cs.server.serverpackets
{
    public class L1PetMatch
    {
        private static Logger _log = Logger.getLogger( typeof( L1PetMatch ).FullName );

        public const int STATUS_NONE = 0;
        public const int STATUS_READY1 = 1;
        public const int STATUS_READY2 = 2;
        public const int STATUS_PLAYING = 3;

        public const int MAX_PET_MATCH = 1;

        private static short[] PET_MATCH_MAPID = { 5125, 5131, 5132, 5133, 5134 };

        private String[] _pc1Name = new String[MAX_PET_MATCH];
        private String[] _pc2Name = new String[MAX_PET_MATCH];
        private L1PetInstance[] _pet1 = new L1PetInstance[MAX_PET_MATCH];
        private L1PetInstance[] _pet2 = new L1PetInstance[MAX_PET_MATCH];

        private static L1PetMatch _instance;

        public static L1PetMatch getInstance()
        {
            if ( _instance == null )
            {
                _instance = new L1PetMatch();
            }
            return _instance;
        }

        public int setPetMatchPc( int petMatchNo, L1PcInstance pc, L1PetInstance pet )
        {
            int status = getPetMatchStatus( petMatchNo );
            if ( status == STATUS_NONE )
            {
                _pc1Name[petMatchNo] = pc.getName();
                _pet1[petMatchNo] = pet;
                return STATUS_READY1;
            }
            else if ( status == STATUS_READY1 )
            {
                _pc2Name[petMatchNo] = pc.getName();
                _pet2[petMatchNo] = pet;
                return STATUS_PLAYING;
            }
            else if ( status == STATUS_READY2 )
            {
                _pc1Name[petMatchNo] = pc.getName();
                _pet1[petMatchNo] = pet;
                return STATUS_PLAYING;
            }
            return STATUS_NONE;
        }

        private int getPetMatchStatus( int petMatchNo )
        {
            lock ( this )
            {
                L1PcInstance pc1 = null;
                if ( _pc1Name[petMatchNo] != null )
                {
                    pc1 = L1World.getInstance().getPlayer( _pc1Name[petMatchNo] );
                }
                L1PcInstance pc2 = null;
                if ( _pc2Name[petMatchNo] != null )
                {
                    pc2 = L1World.getInstance().getPlayer( _pc2Name[petMatchNo] );
                }

                if ( pc1 == null && pc2 == null )
                {
                    return STATUS_NONE;
                }
                if ( pc1 == null && pc2 != null )
                {
                    if ( pc2.getMapId() == PET_MATCH_MAPID[petMatchNo] )
                    {
                        return STATUS_READY2;
                    }
                    else
                    {
                        _pc2Name[petMatchNo] = null;
                        _pet2[petMatchNo] = null;
                        return STATUS_NONE;
                    }
                }
                if ( pc1 != null && pc2 == null )
                {
                    if ( pc1.getMapId() == PET_MATCH_MAPID[petMatchNo] )
                    {
                        return STATUS_READY1;
                    }
                    else
                    {
                        _pc1Name[petMatchNo] = null;
                        _pet1[petMatchNo] = null;
                        return STATUS_NONE;
                    }
                }

                // PCが試合場に2人いる場合
                if ( pc1.getMapId() == PET_MATCH_MAPID[petMatchNo]
                        && pc2.getMapId() == PET_MATCH_MAPID[petMatchNo] )
                {
                    return STATUS_PLAYING;
                }

                // PCが試合場に1人いる場合
                if ( pc1.getMapId() == PET_MATCH_MAPID[petMatchNo] )
                {
                    _pc2Name[petMatchNo] = null;
                    _pet2[petMatchNo] = null;
                    return STATUS_READY1;
                }
                if ( pc2.getMapId() == PET_MATCH_MAPID[petMatchNo] )
                {
                    _pc1Name[petMatchNo] = null;
                    _pet1[petMatchNo] = null;
                    return STATUS_READY2;
                }
                return STATUS_NONE;
            }
        }

        private int decidePetMatchNo()
        {
            // 相手が待機中の試合を探す
            for ( int i = 0; i < MAX_PET_MATCH; i++ )
            {
                int status = getPetMatchStatus( i );
                if ( status == STATUS_READY1 || status == STATUS_READY2 )
                {
                    return i;
                }
            }
            // 待機中の試合がなければ空いている試合を探す
            for ( int i = 0; i < MAX_PET_MATCH; i++ )
            {
                int status = getPetMatchStatus( i );
                if ( status == STATUS_NONE )
                {
                    return i;
                }
            }
            return -1;
        }

        public bool enterPetMatch( L1PcInstance pc, int amuletId )
        {
            lock ( this )
            {
                int petMatchNo = decidePetMatchNo();
                if ( petMatchNo == -1 )
                {
                    return false;
                }

                L1PetInstance pet = withdrawPet( pc, amuletId );
                L1Teleport.teleport( pc, 32799, 32868, PET_MATCH_MAPID[petMatchNo], 0,
                        true );

                L1PetMatchReadyTimer timer = new L1PetMatchReadyTimer( petMatchNo, pc, pet );
                timer.begin();
                return true;
            }
        }

        private L1PetInstance withdrawPet( L1PcInstance pc, int amuletId )
        {
            L1Pet l1pet = PetTable.getInstance().getTemplate( amuletId );
            if ( l1pet == null )
            {
                return null;
            }
            L1Npc npcTemp = NpcTable.getInstance().getTemplate( l1pet.get_npcid() );
            L1PetInstance pet = new L1PetInstance( npcTemp, pc, l1pet );
            pet.setPetcost( 6 );
            return pet;
        }

        public void startPetMatch( int petMatchNo )
        {
            _pet1[petMatchNo].setCurrentPetStatus( 1 );
            _pet1[petMatchNo].setTarget( _pet2[petMatchNo] );

            _pet2[petMatchNo].setCurrentPetStatus( 1 );
            _pet2[petMatchNo].setTarget( _pet1[petMatchNo] );

            L1PetMatchTimer timer = new L1PetMatchTimer( _pet1[petMatchNo],
                    _pet2[petMatchNo], petMatchNo );
            timer.begin();
        }

        public void endPetMatch( int petMatchNo, int winNo )
        {
            L1PcInstance pc1 = L1World.getInstance()
                    .getPlayer( _pc1Name[petMatchNo] );
            L1PcInstance pc2 = L1World.getInstance()
                    .getPlayer( _pc2Name[petMatchNo] );
            if ( winNo == 1 )
            {
                giveMedal( pc1, petMatchNo, true );
                giveMedal( pc2, petMatchNo, false );
            }
            else if ( winNo == 2 )
            {
                giveMedal( pc1, petMatchNo, false );
                giveMedal( pc2, petMatchNo, true );
            }
            else if ( winNo == 3 )
            { // 引き分け
                giveMedal( pc1, petMatchNo, false );
                giveMedal( pc2, petMatchNo, false );
            }
            qiutPetMatch( petMatchNo );
        }


        private void giveMedal( L1PcInstance pc, int petMatchNo, bool isWin )
        {
            if ( pc == null )
            {
                return;
            }
            if ( pc.getMapId() != PET_MATCH_MAPID[petMatchNo] )
            {
                return;
            }
            if ( isWin )
            {
                pc.sendPackets( new S_ServerMessage( 1166, pc.getName() ) ); // %0%sペットマッチで勝利を収めました。
                L1ItemInstance item = ItemTable.getInstance().createItem( 41309 );
                int count = 3;
                if ( item != null )
                {
                    if ( pc.getInventory().checkAddItem( item, count ) == L1Inventory.OK )
                    {
                        item.setCount( count );
                        pc.getInventory().storeItem( item );
                        pc.sendPackets( new S_ServerMessage( 403, item.getLogName() ) ); // %0を手に入れました。
                    }
                }
            }
            else
            {
                L1ItemInstance item = ItemTable.getInstance().createItem( 41309 );
                int count = 1;
                if ( item != null )
                {
                    if ( pc.getInventory().checkAddItem( item, count ) == L1Inventory.OK )
                    {
                        item.setCount( count );
                        pc.getInventory().storeItem( item );
                        pc.sendPackets( new S_ServerMessage( 403, item.getLogName() ) ); // %0を手に入れました。
                    }
                }
            }
        }

        private void qiutPetMatch( int petMatchNo )
        {
            L1PcInstance pc1 = L1World.getInstance()
                    .getPlayer( _pc1Name[petMatchNo] );
            if ( pc1 != null && pc1.getMapId() == PET_MATCH_MAPID[petMatchNo] )
            {
                foreach ( Object l1object in pc1.getPetList().Values )
                {
                    if ( l1object is L1PetInstance )
                    {
                        L1PetInstance pet = (L1PetInstance)l1object;
                        pet.dropItem();
                        pc1.getPetList().Remove( pet.getId() );
                        pet.deleteMe();
                    }
                }
                L1Teleport.teleport( pc1, 32630, 32744, (short)4, 4, true );
            }
            _pc1Name[petMatchNo] = null;
            _pet1[petMatchNo] = null;

            L1PcInstance pc2 = L1World.getInstance().getPlayer( _pc2Name[petMatchNo] );
            if ( pc2 != null && pc2.getMapId() == PET_MATCH_MAPID[petMatchNo] )
            {
                foreach ( Object l1object in pc2.getPetList().Values )
                {
                    if ( l1object is L1PetInstance )
                    {
                        L1PetInstance pet = (L1PetInstance)l1object;
                        pet.dropItem();
                        pc2.getPetList().Remove( pet.getId() );
                        pet.deleteMe();
                    }
                }
                L1Teleport.teleport( pc2, 32630, 32744, (short)4, 4, true );
            }
            _pc2Name[petMatchNo] = null;
            _pet2[petMatchNo] = null;
        }

        public class L1PetMatchReadyTimer
        {
            private Logger _log = Logger.getLogger( typeof( L1PetMatchReadyTimer ).FullName );

            private int _petMatchNo;
            private L1PcInstance _pc;
            private L1PetInstance _pet;
            Timer timer;
            public L1PetMatchReadyTimer( int petMatchNo, L1PcInstance pc, L1PetInstance pet )
            {
                _petMatchNo = petMatchNo;
                _pc = pc;
                _pet = pet;
            }

            public void begin()
            {
                //Timer timer = new Timer();
                //timer.schedule(this, 3000);
                timer = new Timer( new TimerCallback( run ), null, 3000, Timeout.Infinite );
            }

            public void run( object state )
            {
                for ( ; ; )
                {
                    Thread.Sleep( 1000 );
                    if ( _pc == null || _pet == null )
                    {
                        timer.Dispose();
                        return;
                    }

                    if ( _pc.isTeleport() )
                    {
                        continue;
                    }
                    if ( L1PetMatch.getInstance().setPetMatchPc( _petMatchNo, _pc,
                            _pet ) == L1PetMatch.STATUS_PLAYING )
                    {
                        L1PetMatch.getInstance().startPetMatch( _petMatchNo );
                    }
                    timer.Dispose();
                    return;
                }
            }
        }

        public class L1PetMatchTimer
        {
            private Logger _log = Logger.getLogger( typeof( L1PetMatchTimer ).FullName );

            private L1PetInstance _pet1;
            private L1PetInstance _pet2;
            private int _petMatchNo;
            private int _counter = 0;
            private Timer timer;

            public L1PetMatchTimer( L1PetInstance pet1, L1PetInstance pet2, int petMatchNo )
            {
                _pet1 = pet1;
                _pet2 = pet2;
                _petMatchNo = petMatchNo;
            }

            public void begin()
            {
                //Timer timer = new Timer();
                //timer.schedule(this, 0);
                timer = new Timer( new TimerCallback( run ), null, 0, Timeout.Infinite );
            }

            public void run( object state )
            {
                for ( ; ; )
                {
                    Thread.Sleep( 3000 );
                    _counter++;
                    if ( _pet1 == null || _pet2 == null )
                    {
                        timer.Dispose();
                        return;
                    }

                    if ( _pet1.isDead() || _pet2.isDead() )
                    {
                        int winner = 0;
                        if ( !_pet1.isDead() && _pet2.isDead() )
                        {
                            winner = 1;
                        }
                        else if ( _pet1.isDead() && !_pet2.isDead() )
                        {
                            winner = 2;
                        }
                        else
                        {
                            winner = 3;
                        }
                        L1PetMatch.getInstance().endPetMatch( _petMatchNo, winner );
                        timer.Dispose();
                        return;
                    }

                    if ( _counter == 100 )
                    {
                        // 5分経っても終わらない場合は引き分け
                        L1PetMatch.getInstance().endPetMatch( _petMatchNo, 3 );
                        timer.Dispose();
                        return;
                    }
                }
            }
        }
    }
}
